import re
import keyword

# 处理表达式的匹配,用于对查找到的变量的内容(${...}中的内容或者if中的内容)进一步处理.
# 使用方式,在用正则查找出表达式之后,设置要进一步处理的正则和处理方法,然后设置match.sub的repo方法为regex_sub_repo,
from not_so_free_marker.statics import regNumber


# 替换元素用的.
class ExpressProc():
    def __init__(self):
        # 匹配任意,返回原文
        self.regex = re.compile(".*")
        self.process_func = lambda x: x.group(0)
        self.formatStr = "{0}"  # 规则:替换这个东西

    def regex_sub_repo(self, m: re.match):
        return self.formatStr.format(self.__private__process_by_rule(m.group(1)))

    def __private__process_by_rule(self, content: str):
        return self.regex.sub(self.process_func, content)


class ExpressProc2():
    def __init__(self):
        # 匹配任意,返回原文
        self.regex = re.compile(".*")
        self.process_func = lambda x: x.group(0)
        self.formatStr = "{0} {1}"  # 规则:替换第一个,保留第二个.

    def regex_sub_repo(self, m: re.match):  # 就这里和ExpressProc有差别,
        return self.formatStr.format(self.__private__process_by_rule(m.group(1)), m.group(2))

    def __private__process_by_rule(self, content: str):
        return self.regex.sub(self.process_func, content)


# 把a.b.c这样的数据从字典中取出来(data["a"]["b"]["c"]).
# 如果字典中不存在这样条数据
# 则返回原文
def dotted_str_to_map(var_str: str, data: dict):
    prop_list = var_str.split(".")
    new_obj = data
    for prop in prop_list:
        # 如果是属性名是数字,并且数据是list,按照数组索引的方式取
        if isinstance(new_obj, list):
            if prop.isdecimal():  # 想通过索引取元素
                if len(new_obj) > int(prop):
                    new_obj = new_obj[int(prop)]
                else:  # 出错了,索引大于列表长度,返回原文
                    return var_str
            else:  # 想取其中的一个元素的属性
                new_obj = new_obj[0].get(prop)
        else:
            new_obj = new_obj.get(prop)
        if new_obj is None:  # 出错了,找不到这个数据,返回原文
            return var_str
    return new_obj


def is_number(var: str):
    mat = regNumber.match(var)
    return mat is not None


def is_keyword(var: str):
    return keyword.iskeyword(var.strip())
